package reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Scanner;

public class ReflectionTest {
    public static void main(String[] args) throws ReflectiveOperationException {
        String name;
        if (args.length > 0) {
            name = args[0];
        }
        else {
            try (var in = new Scanner(System.in)) {
                System.out.println("Enter class name (e.g. java.util.Date): ");
                name = in.next();
            }
        }

        Class<?> cl = Class.forName(name);

        // 修饰符，例如 public abstract之类的
        String modifiers = Modifier.toString(cl.getModifiers());
        if (modifiers.length() > 0) {
            System.out.print(modifiers + " ");
        }

        // 密封属性
        if (cl.isSealed()) {
            System.out.print("sealed ");
        }

        // 枚举类
        if (cl.isEnum()) {
            System.out.print("enum " + name);
        }
        // 记录类
        else if (cl.isRecord()) {
            System.out.print("record " + name);
        }
        // 接口类
        else if (cl.isInterface()) {
            System.out.print("interface " + name);
        }
        // 一般类
        else {
            System.out.print("class " + name);
        }

        // 打印超类
        // 如果cl是 Object 或者 接口 或者原生包装类，例如 Integer 之类，则没有超类
        // getSuperclass方式仅使用类的继承关系，不适用接口之间的继承
        Class<?> supercl = cl.getSuperclass();
        if (supercl != null && supercl != Object.class) {
            System.out.print(" extends " + supercl.getName());
        }

        // 打印接口
        printInterfaces(cl);

        // 打印允许的子类
        printPermittedSubclasses(cl);

        System.out.print(" {\n");

        // 打印字段
        printFields(cl);

        // 打印构造器
        System.out.println();
        printConstructors(cl);

        // 打印方法
        System.out.println();
        printMethods(cl);

        System.out.println("}");
    }

    // 打印接口
    public static void printInterfaces(Class<?> cl) {
        Class<?>[] interfaces = cl.getInterfaces();
        for (int i = 0; i < interfaces.length; i++) {
            System.out.print(i == 0 ? (cl.isInterface() ? " extends " : " implements ") : ", ");
            System.out.print(interfaces[i].getName());
        }
    }

    // 打印允许的子类
    public static void printPermittedSubclasses(Class<?> cl) {
        if (cl.isSealed()) {
            Class<?>[] cls = cl.getPermittedSubclasses();
            for (int i = 0; i < cls.length; i++) {
                System.out.print(i == 0 ? " permits " : ", ");
                System.out.print(cls[i].getName());
            }
        }
    }

    // 打印字段
    public static void printFields(Class<?> cl) {
        Field[] fields = cl.getDeclaredFields();
        for (Field f : fields) {
            System.out.print("    ");

            // 修饰符
            String modifiers = Modifier.toString(f.getModifiers());
            if (modifiers.length() > 0) {
                System.out.print(modifiers + " ");
            }

            // 字段类型 和 字段名
            System.out.println(f.getType().getName() + " " + f.getName() + ";");
        }
    }

    // 打印构造器
    public static void printConstructors(Class<?> cl) {
        Constructor<?>[] constructors = cl.getDeclaredConstructors();
        for (Constructor<?> c : constructors) {
            System.out.print("    ");

            // 修饰符
            String modifiers = Modifier.toString(c.getModifiers());
            if (modifiers.length() > 0) {
                System.out.print(modifiers + " ");
            }

            // 构造器名称
            String name = c.getName();
            System.out.print(name + "(");

            // 参数类型列表
            Class<?>[] paramTypes = c.getParameterTypes();
            for (int j = 0; j < paramTypes.length; j++) {
                if (j > 0) {
                    System.out.print(", ");
                }
                System.out.print(paramTypes[j].getName());
            }
            System.out.println(");");
        }
    }

    // 打印方法
    public static void printMethods(Class<?> cl) {
        Method[] methods = cl.getDeclaredMethods();

        for (Method m : methods) {
            System.out.print("    ");

            // 修饰符
            String modifiers = Modifier.toString(m.getModifiers());
            if (modifiers.length() > 0) {
                System.out.print(modifiers + " ");
            }

            // 返回值类型
            Class<?> returnType = m.getReturnType();
            System.out.print(returnType.getName() + " ");

            // 方法名
            System.out.print(m.getName() + "(");

            // 参数类型列表
            Class<?>[] paramTypes = m.getParameterTypes();
            for (int j = 0; j < paramTypes.length; j++) {
                if (j > 0) {
                    System.out.print(", ");
                }
                System.out.print(paramTypes[j].getName());
            }

            System.out.println(");");
        }
    }
}
